using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using EasyProjects.Client;
using EasyProjects.ClientModel.Entities;

namespace EasyProjects.TimeLogger
{
    /// <summary>
    /// Implemention working with API
    /// </summary>
    public class ObjectsHelper
    {
        #region Fields
        private static object locker = new object();
        private static ObjectsHelper instance = null;
        private HttpClient client = null;

        private List<Project> projects = new List<Project>();
        private Dictionary<Project, List<Task>> tasks = new Dictionary<Project, List<Task>>();
        #endregion

        #region .ctor
        /// <summary>
        /// Initializes a new instance of the <see cref="ObjectsHelper"/> class.
        /// </summary>
        private ObjectsHelper()
        {
        }
        #endregion

        #region Client
        /// <summary>
        /// Gets the instance.
        /// </summary>
        /// <value>The instance.</value>
        public HttpClient Client
        {
            get {
                if(client == null)
                    client = new HttpClient(Properties.Settings.Default.EasyProjectsApiUrl.TrimEnd('/') + "/rest/v1/", true, Properties.Settings.Default.User, Properties.Settings.Default.Password);
                
                return client;
            }
        }
        #endregion

        #region UpdateClient
        /// <summary>
        /// Updates the client.
        /// </summary>
        public void UpdateClient()
        {
            client = null;
        }
        #endregion

        #region Instance
        /// <summary>
        /// Gets the instance.
        /// </summary>
        /// <value>The instance.</value>
        public static ObjectsHelper Instance
        {
            get
            {
                lock (locker) //prevent multiply usage this method
                {
                    if (instance == null)
                    {
                        instance = new ObjectsHelper();
                        instance.client = new HttpClient(Properties.Settings.Default.EasyProjectsApiUrl, true, Properties.Settings.Default.User, Properties.Settings.Default.Password);
                    }
                    return instance;
                }
            }
        }
        #endregion

        #region Update
        /// <summary>
        /// Update all data async
        /// </summary>
        public void Update()
        {
            //Clean all data
            RaiseDataUpdating();
            //api = null;
            userID = 0;
            projects = new List<Project>();
            tasks = new Dictionary<Project, List<Task>>();
            MethodInvoker simpleDelegate = new MethodInvoker(asyncUpdate);
            simpleDelegate.BeginInvoke(null, null);
        }

        //retrieve data from server
        private void asyncUpdate()
        {
            try
            {
                getProjects();

                foreach (Project project in projects)
                {
                    List<Task> tmp = new List<Task>();
                    getTasks(project, tmp);
                    tasks.Add(project, tmp);
                }
                RaiseDataUpdated();

            }
            catch (Exception)
            {
                RaiseDataUpdated();
            }
            
        }
        #endregion

        #region SaveEntry
        /// <summary>
        /// Send time entry on Ep server
        /// </summary>
        /// <param name="project"></param>
        /// <param name="task"></param>
        /// <param name="description"></param>
        /// <param name="entryDate"></param>
        /// <param name="hours"></param>
        /// <param name="isBillable"></param>
        /// <returns>True if success.</returns>
        public bool SaveEntry(Project project, Task task, string description, DateTime entryDate, float hours,
                              bool isBillable)
        {
            TimeEntry timelog = new TimeEntry();
            timelog.TaskID = task.TaskID;
            timelog.UserID = UserID;
            timelog.Duration = Convert.ToDecimal(hours);
            timelog.Description = description;
            timelog.EntryDate = entryDate;
            timelog.Billable = isBillable;

            client.Post<TimeEntry>(timelog);
            return true;
        }
        #endregion

        #region TasksByProject
        /// <summary>
        /// Return task list specified for selected project.
        /// </summary>
        /// <param name="project">Project for task finding.</param>
        /// <returns>Tasks array list.</returns>
        public IList TasksByProject(Project project)
        {
            if ((project == null) || (!tasks.ContainsKey(project)))
                return new List<Project>();

            return (IList)tasks[project];
        }
        #endregion

        #region Projects
        /// <summary>
        /// return projects list
        /// </summary>
        public List<Project> Projects
        {
            get { return projects; }
        }
        #endregion

        #region DataUpdatingHandler

        public delegate void DataUpdatedHandler(object sender, EventArgs e);

        /// <summary>
        /// Occurs when [data updated].
        /// </summary>
        public event DataUpdatedHandler DataUpdated;

        /// <summary>
        /// Rase dataupdated event for updting IU and other stuff
        /// </summary>
        private void RaiseDataUpdated()
        {
            if (DataUpdated != null)
                DataUpdated(this, EventArgs.Empty);
        }

        public delegate void DataUpdatingHandler(object sender, EventArgs e);

        public event DataUpdatingHandler DataUpdating;

        /// <summary>
        /// Raise DataUptating event. when starts to recieve data from server.
        /// </summary>
        private void RaiseDataUpdating()
        {
            if (DataUpdating != null)
                DataUpdating(this, EventArgs.Empty);
        }

        #endregion

        #region UserID

        private int userID;
        
        /// <summary>
        /// Returns EP UserID
        /// </summary>
        private int UserID
        {
            get
            {
                if (userID == 0)
                {
                    var user = Client.Query<User>().Where(u => u.Login == Properties.Settings.Default.User).ToList().First();

                    userID = user.UserID;
                }
                return userID;
            }
        }

        #endregion

        #region getProjects
        /// <summary>
        /// Get projects from EP
        /// </summary>
        private void getProjects()
        {
            //get projects where current user is project member
            projects = Client.QueryAsResource<Project>("myprojects").ToList();
            //filter projects
            projects = projects.Where(proj => proj.Status().TreatAsCompleted == false).ToList();
        }
        #endregion
        #region getTasks
        /// <summary>
        /// Gets the tasks.
        /// </summary>
        /// <param name="project">The project.</param>
        /// <param name="tasksList">The tasks list.</param>
        private void getTasks(Project project, List<Task> tasksList)
        {
            //get task from EP for selected project
            var tasks = Client.QueryAsResource<Task>("myactivities").Where(p => p.ProjectID == project.ProjectID).ToList();
            tasksList.AddRange(tasks.Where(tsk => tsk.Status().TreatAsCompleted == false).Where(p2 => p2.CanCreateTimeEntries == true).ToList());
        }
        #endregion
        
    }

}